﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Medianamik.Core.DAL.Services;
using Medianamik.Core.Interfaces;
using Medianamik.Core.Sugar;
using SubSonic;

namespace Medianamik.Core.DAL.Repositories
{
    public interface IMedianamikRepository<TItem> : INodeRepository
        where TItem : IMedianamikDTO
    {
        INodeMapper NodeMapper { get; }

        ICultureService CultureService { get; }

        IContentStateService ContentStateService { get; }

        PagedCollection<TItem> PagedWithFilters(CultureInfo editionCulture, int pageIndex, int pageSize,
          ActiveStatus contentStatus, Guid? baseTypeId, Guid? moduleNodeId, DateTime? startDate,
           DateTime? endDate, string keywords, string orderBy,
           IEnumerable<Where> additionalWheres, bool withTypeInheritance);

        PagedCollection<TItem> PagedWithFilters(bool multiLingual, CultureInfo culture, int pageIndex,
            int pageSize, ActiveStatus status, Guid? typeId, Guid? parentId, DateTime? startDate,
            DateTime? endDate, string keywords, string orderBy,
            IEnumerable<Where> additionalWheres, IEnumerable<BetweenAnd> additionalBetweenAnds, bool withTypeInheritance);

        PagedCollection<TItem> PagedWithFilters(CultureInfo editionCulture, int pageIndex, int pageSize,
                Guid baseTypeId, Guid moduleNodeId, IEnumerable<Where> additionalWheres);

        TItem Get(Guid nodeId);
        TItem Get(Guid nodeId, CultureInfo culture, ContentState contentState);

        TItem Get(Guid nodeId, CultureInfo culture, ContentState contentState, 
                                  ActiveStatus activeStatus);

        IList<TItem> GetWithFilters(Guid? typeId, Guid? parentId, 
            IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd, string orderByString,
            int? depth, bool withTypeInheritance);

        PagedCollection<TItem> PagedWithFilters(int pageIndex, int pageSize,
            Guid? typeId, Guid? parentId, IEnumerable<Where> wheres, 
            IEnumerable<BetweenAnd> betweensAnd,
            string orderByString, int? depth, bool withTypeInheritance);

        IList<TItem> ChildsOf(Guid nodeId, bool inclusive, int maxDepth);
        IList<TItem> ParentsOf(Guid nodeId, bool inclusive, int maxDepth);
        IEnumerable<TItem> LoadByIDs(string ids);
        IEnumerable<TItem> LoadByIDs(IList<Guid> ids);
        IList<TItem> All();

        IList<TItem> GetWithFilters(CultureInfo culture,
            ContentState contentState, ActiveStatus status,
            Guid? typeId, Guid? parentId, IEnumerable<Where> wheres,
            IEnumerable<BetweenAnd> betweensAnd, string orderByString,
            int? depth, bool withTypeInheritance);

        PagedCollection<TItem> PagedWithFilters(CultureInfo culture,
            ContentState contentState, ActiveStatus status, int pageIndex, int pageSize, Guid? typeId,
            Guid? parentId, IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd,
            string orderByString, int? depth, bool withTypeInheritance);

        PagedCollection<TItem> PagedWithFilters(bool multiLingual, CultureInfo culture,
            ContentState contentState, ActiveStatus status, int pageIndex, int pageSize, Guid? typeId,
            Guid? parentId, IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd,
            string orderByString, int? depth, bool withTypeInheritance);

        IList<TItem> ChildsOf(Guid nodeId, bool inclusive, int maxDepth,
            CultureInfo culture, ContentState contentState, ActiveStatus status);

        IList<TItem> ParentsOf(Guid nodeId, bool inclusive, int maxDepth,
            CultureInfo culture, ContentState contentState, ActiveStatus status);

        IEnumerable<TItem> LoadByIDs(string ids, string cultureName, ContentState contentState,
            ActiveStatus status);

        IEnumerable<TItem> LoadByIDs(IList<Guid> ids, string cultureName,
            ContentState contentState, ActiveStatus status);

        IList<TItem> All(CultureInfo culture, ContentState contentState,
                                         ActiveStatus status);

        void DeleteByParent(Guid parendId, bool destroy);

        void DeleteBranch(Guid nodeId, bool destroy);

        void Delete(TItem item);

        void MapAndSaveItem<T>(T item) where T : IMedianamikDTO;
        void MapAndSaveItem<T>(T item, MappingOptions options) where T : IMedianamikDTO;

        void MapAndSaveItems<T>(IEnumerable<T> item) where T : IMedianamikDTO;
        void MapAndSaveItems<T>(IEnumerable<T> item, MappingOptions options) where T : IMedianamikDTO;

        void MapAndPublishItem<T>(T item) where T : IMedianamikDTO;
        void MapAndPublishItem<T>(T item, MappingOptions options) where T : IMedianamikDTO;

        void MapAndPublishItems<T>(IEnumerable<T> item) where T : IMedianamikDTO;
        void MapAndPublishItems<T>(IEnumerable<T> item, MappingOptions options) where T : IMedianamikDTO;

        void Delete(Guid nodeId, bool destroy);

        IList<TItem> GetWithFilters(bool multiLingual, CultureInfo culture,
                                    ActiveStatus status, Guid? typeId, Guid? parentId, DateTime? startDate,
                                    DateTime? endDate, string keywords, string orderBy,
                                    IEnumerable<Where> additionalWheres,
                                    bool withTypeInheritance);

        IList<TItem> AllInstances();
        IList<TItem> AllInstances(ContentState contentState, ActiveStatus status);
        IList<TItem> AllInstances(Guid nodeId);
        IList<TItem> AllInstances(Guid nodeId, ContentState contentState, ActiveStatus status);

        IList<TItem> AlllInstancesWithFilters(ContentState contentState, ActiveStatus status,
                                                              Guid? typeId, Guid? parentId, IEnumerable<Where> wheres,
                                                              IEnumerable<BetweenAnd> betweensAnd, string orderByString,
                                                              int? depth, bool withTypeInheritance);

        IList<TItem> AlllInstancesWithFilters(Guid? typeId, Guid? parentId, 
                                                              IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd, string orderByString,
                                                              int? depth, bool withTypeInheritance);
    }

    public class MedianamikRepository<TCollection, TItem> : 
        IMedianamikRepository<TItem> 
        where TCollection : ICollectionWithChildren<TCollection, TItem>, new()
        where TItem : IMedianamikDTO, IRecordBase, new()
    {
        private readonly ICultureService _cultureService;
        private readonly IContentStateService _contentStateService;
        private readonly INodeMapper _nodeMapper;

        public MedianamikRepository(ICultureService cultureService,
            IContentStateService contentStateService, INodeMapper nodeMapper)
        {
            _cultureService = cultureService;
            _contentStateService = contentStateService;
            _nodeMapper = nodeMapper;
        }

        public INodeMapper NodeMapper
        {
            get { return _nodeMapper; }
        }

        public ICultureService CultureService
        {
            get { return _cultureService; }
        }

        public IContentStateService ContentStateService
        {
            get { return _contentStateService; }
        }

        public virtual void Reorder(Guid id, Guid destinationId, DropPosition position)
        {
            NodeManager.ChangeNodeOrder(NodeManager.GetNode(id), destinationId, position);
        }

        public virtual void SetActiveStatus(Guid id, CultureInfo culture, ActiveStatus status)
        {
            NodeManager.SetNodeActiveStatus(id, culture, status == ActiveStatus.Activated);
        }

        public void SaveNodes(IEnumerable<Node> nodes)
        {
            NodeManager.SaveNodes(nodes);
        }

        public virtual INodeWrapper NewNode(IMedianamikDTO dto)
        {
            return NewNode(dto, true);
        }
        public virtual INodeWrapper NewNode(IMedianamikDTO dto, bool validateHierarchicalRules)
        {
            return NodeManager.NewNode<NodeWrapper>(dto.NodeId == default(Guid) ? Guid.NewGuid() : dto.NodeId, dto.TypeId,
                    CultureInfo.GetCultureInfo(dto.CultureName), dto.ParentNodeId, validateHierarchicalRules);
        }

        public virtual INodeWrapper GetExistingNode(IMedianamikDTO dto)
        {
            return NodeManager.GetNode<NodeWrapper>(dto.NodeId);
        }

        public virtual void SaveNode(INodeWrapper node)
        {
            NodeManager.SaveNode(node);
        }

        public virtual void PublishNode(INodeWrapper node, CultureInfo culture)
        {
            NodeManager.PublishNode(node.InnerNode.ID, culture);
        }

        public virtual void SaveNodeHandlingPositionAndParentNodeId(INodeWrapper node,
            Guid? parentNodeId, short? position)
        {
            if (parentNodeId.HasValue)
                node.InnerNode.ParentID = parentNodeId;
            if (position.HasValue)
                node.InnerNode.Position = position.Value;
            NodeManager.SaveNode(node);
        }

        public virtual void PublishNodeHandlingPositionAndParentNodeId(INodeWrapper node,
            Guid? parentNodeId, short? position, CultureInfo culture)
        {
            SaveNodeHandlingPositionAndParentNodeId(node, parentNodeId, position);
            NodeManager.PublishNode(node.InnerNode.ID, culture);
        }

        public void DeleteBranch(Guid nodeId, bool destroy)
        {
            NodeManager.DeleteBranch(nodeId, destroy);
        }

        public void Delete(TItem item)
        {
            NodeManager.DeleteNode(item.NodeId);
        }

        #region Map And Save

        public void MapAndSaveItem<T>(T item, MappingOptions options) where T : IMedianamikDTO
        {
            NodeManager.SaveNode(NodeMapper.MapNode(item, options));
        }
        public void MapAndSaveItem<T>(T item) where T : IMedianamikDTO
        {
            MapAndSaveItem(item, MappingOptions.DefaultOptions);
        }

        public void MapAndSaveItems<T>(IEnumerable<T> items, MappingOptions options) where T : IMedianamikDTO
        {
            NodeManager.SaveNodes(items.Select(item =>
                NodeMapper.MapNode(item, options).InnerNode));
        }
        public void MapAndSaveItems<T>(IEnumerable<T> items) where T : IMedianamikDTO
        {
            MapAndSaveItems(items, MappingOptions.DefaultOptions);
        }

        public void MapAndPublishItem<T>(T item, MappingOptions options) where T : IMedianamikDTO
        {
            var node = NodeMapper.MapNode(item, options).InnerNode;

            node.Instances.ForEach(i => i.ToBePublished = true);

            NodeManager.SaveNode(node);
        }
         public void MapAndPublishItem<T>(T item) where T : IMedianamikDTO
         {
             MapAndPublishItem(item, MappingOptions.DefaultOptions);
         }

        public void MapAndPublishItems<T>(IEnumerable<T> items, MappingOptions options) where T : IMedianamikDTO
        {
            var nodes = items.Select(item =>
                NodeMapper.MapNode(item, options).InnerNode);

            nodes.ForEach(node => node.Instances.ForEach(i => i.ToBePublished = true));

            NodeManager.SaveNodes(nodes);
        }
        public void MapAndPublishItems<T>(IEnumerable<T> items) where T : IMedianamikDTO
        {
            MapAndPublishItems(items, MappingOptions.DefaultOptions);
        }

        #endregion

        public void Delete(Guid nodeId, bool destroy)
        {
            if(destroy)
            NodeManager.DestroyNode(nodeId);
            else
                NodeManager.DeleteNode(nodeId);
        }

        public virtual IList<TItem> GetWithFilters(bool multiLingual, CultureInfo culture,
            ActiveStatus status, Guid? typeId, Guid? parentId, DateTime? startDate,
            DateTime? endDate, string keywords, string orderBy, IEnumerable<Where> additionalWheres,
            bool withTypeInheritance)
        {
            var wheres = additionalWheres == null ? new List<Where>() : additionalWheres.ToList();

            if (startDate.HasValue)
            {
                wheres.Add(new Where
                {
                    ColumnName = "CreatedOn",
                    Comparison = Comparison.GreaterOrEquals,
                    ParameterValue = startDate.Value
                });
            }

            if (endDate.HasValue)
            {
                wheres.Add(new Where
                {
                    ColumnName = "CreatedOn",
                    Comparison = Comparison.LessOrEquals,
                    ParameterValue = endDate.Value
                });
            }

            if (!String.IsNullOrEmpty(keywords))
            {
                wheres.Add(new Where
                {
                    ColumnName = "Name",
                    Comparison = Comparison.Like,
                    ParameterValue = '%' + keywords + '%'
                });
            }

            var finalOrderBy = "createdon desc";

            if (!orderBy.IsNullOrEmptyTrim())
                finalOrderBy = orderBy.Trim();

            return GetWithFilters(multiLingual, culture, ContentState.Draft, status, typeId, parentId, wheres, null,
                                  finalOrderBy, 1, withTypeInheritance);
        }

        public virtual IList<TItem> GetWithFilters(bool multiLingual, CultureInfo culture,
            ContentState contentState, ActiveStatus status,
            Guid? typeId, Guid? parentId, IEnumerable<Where> wheres,
            IEnumerable<BetweenAnd> betweensAnd, string orderByString,
            int? depth, bool withTypeInheritance)
        {
            var query = new Query(new TItem().GetSchema());

            query = AddCultureAndContentStateFilter(multiLingual, query, contentState, culture);
            query = AddStatusFilter(query, status);
            query = AddParentIdFilter(query, parentId, depth);
            query = AddTypeIdFilter(query, typeId, withTypeInheritance);
            query = AddCustomWheresFilter(query, wheres);
            query = AddBetweensAndFilter(query, betweensAnd);
            query = AddOrderByStatement(query, orderByString);

            var collection = new TCollection();
            collection.LoadAndCloseReader(query.ExecuteReader());
            return collection;
        }

        public virtual IList<TItem> GetWithFilters(CultureInfo culture,
            ContentState contentState, ActiveStatus status,
            Guid? typeId, Guid? parentId, IEnumerable<Where> wheres,
            IEnumerable<BetweenAnd> betweensAnd, string orderByString,
            int? depth, bool withTypeInheritance)
        {
            return GetWithFilters(false, culture, contentState, status, typeId, parentId, wheres, betweensAnd,
                                  orderByString, depth, withTypeInheritance);
        }

        public virtual PagedCollection<TItem> PagedWithFilters(CultureInfo culture,
            ContentState contentState, ActiveStatus status, int pageIndex, int pageSize, Guid? typeId,
            Guid? parentId, IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd,
            string orderByString, int? depth, bool withTypeInheritance)
        {
            return PagedWithFilters(false, culture,
             contentState, status, pageIndex, pageSize, typeId,
            parentId, wheres, betweensAnd,
             orderByString, depth, withTypeInheritance);
        }

        public virtual PagedCollection<TItem> PagedWithFilters(bool multiLingual, CultureInfo culture,
            ContentState contentState, ActiveStatus status, int pageIndex, int pageSize, Guid? typeId,
            Guid? parentId, IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd,
            string orderByString, int? depth, bool withTypeInheritance)
        {
            if (pageIndex == 0)
                throw new Exception("PageIndex is a one-based index.");

            var query = new Query(new TItem().GetSchema())
            {
                PageSize = pageSize,
                PageIndex = pageIndex
            };

            query = AddCultureAndContentStateFilter(multiLingual, query, contentState, culture);
            query = AddStatusFilter(query, status);
            query = AddParentIdFilter(query, parentId, depth);
            query = AddTypeIdFilter(query, typeId, withTypeInheritance);
            query = AddCustomWheresFilter(query, wheres);
            query = AddBetweensAndFilter(query, betweensAnd);
            query = AddOrderByStatement(query, orderByString);

            var collection = new TCollection();
            collection.LoadAndCloseReader(query.ExecuteReader());

            query.PageIndex = 0;
            query.PageSize = 0;

            return new PagedCollection<TItem>(collection,
                query.GetRecordCount());
        }

        public virtual IList<TItem> ChildsOf(Guid nodeId, bool inclusive, int maxDepth,
            CultureInfo culture, ContentState contentState, ActiveStatus status)
        {
            return new TCollection()
                .LoadChildNodes(nodeId, culture.Name, inclusive, maxDepth, contentState, status);
        }

        public virtual IList<TItem> ParentsOf(Guid nodeId, bool inclusive, int maxDepth,
            CultureInfo culture, ContentState contentState, ActiveStatus status)
        {
            return new TCollection()
                .LoadParentNodes(nodeId, culture.Name, inclusive, maxDepth, contentState, status);
        }

        public IEnumerable<TItem> LoadByIDs(string ids, string cultureName, ContentState contentState,
            ActiveStatus status)
        {
            return new TCollection()
                .LoadByIDs(ids, cultureName, contentState, status);
        }

        public IEnumerable<TItem> LoadByIDs(IList<Guid> ids, string cultureName,
            ContentState contentState, ActiveStatus status)
        {
            return new TCollection()
            .LoadByIDs(ids, cultureName, contentState, status);
        }

        public virtual IList<TItem> All(CultureInfo culture, ContentState contentState,
            ActiveStatus status)
        {
            return new TCollection().Load(culture.Name, contentState, status);
        }

        public void DeleteByParent(Guid parendId, bool destroy)
        {
            NodeManager.DeleteByParent(parendId, destroy);
        }

        public virtual IList<TItem> AllInstances(Guid nodeId)
        {
            return AllInstances(nodeId, ContentStateService.GetCurrentContentState(), ActiveStatus.Activated);
        }

        public virtual IList<TItem> AllInstances(Guid nodeId, ContentState contentState, ActiveStatus status)
        {
            Query query = new Query(new TItem().GetSchema());
            query.AddWhere("NodeId", nodeId);

            if (contentState != ContentState.All)
                query.AddWhere("Generation", (int)contentState);

            query = AddStatusFilter(query, status);

            var allInstances = new TCollection();
            allInstances.LoadAndCloseReader(query.ExecuteReader());

            return allInstances.ToList();
        }

        public virtual IList<TItem> AllInstances(ContentState contentState, ActiveStatus status)
        {
            var query = new Query(new TItem().GetSchema());

            if (contentState != ContentState.All)
                query.AddWhere("Generation", (int)contentState);

            query = AddStatusFilter(query, status);

            var allInstances = new TCollection();
            allInstances.LoadAndCloseReader(query.ExecuteReader());

            return allInstances.ToList();
        }

        public virtual IList<TItem> AllInstances()
        {
            var query = new Query(new TItem().GetSchema());

            var contentState = ContentStateService.GetCurrentContentState();
            if (contentState != ContentState.All)
                query.AddWhere("Generation", (int)contentState);

            query = AddStatusFilter(query, ActiveStatus.Activated);

            var allInstances = new TCollection();
            allInstances.LoadAndCloseReader(query.ExecuteReader());

            return allInstances.ToList();
        }

        public virtual IList<TItem> AlllInstancesWithFilters(ContentState contentState, ActiveStatus status,
            Guid? typeId, Guid? parentId, IEnumerable<Where> wheres,
            IEnumerable<BetweenAnd> betweensAnd, string orderByString,
            int? depth, bool withTypeInheritance)
        {
            var query = new Query(new TItem().GetSchema());

            if(contentState != ContentState.All)
                query.AddWhere("Generation", (int) contentState);

            query = AddStatusFilter(query, status);
            query = AddParentIdFilter(query, parentId, depth);
            query = AddTypeIdFilter(query, typeId, withTypeInheritance);
            query = AddCustomWheresFilter(query, wheres);
            query = AddBetweensAndFilter(query, betweensAnd);
            query = AddOrderByStatement(query, orderByString);

            var collection = new TCollection();
            collection.LoadAndCloseReader(query.ExecuteReader());
            return collection;
        }

        public virtual IList<TItem> AlllInstancesWithFilters(Guid? typeId, Guid? parentId, 
            IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd, string orderByString,
            int? depth, bool withTypeInheritance)
        {
            return AlllInstancesWithFilters(ContentStateService.GetCurrentContentState(), 
                ActiveStatus.Activated, typeId, parentId, wheres, betweensAnd, 
                orderByString, depth, withTypeInheritance);
        }

        protected Query AddOrderByStatement(Query query, string orderByString)
        {
            if (!string.IsNullOrEmpty(orderByString))
            {
                query.OrderByCollection = new OrderByCollection();
                query.ORDER_BY(orderByString);
            }

            return query;
        }

        protected Query AddBetweensAndFilter(Query query, IEnumerable<BetweenAnd> betweensAnd)
        {
            if (betweensAnd != null)
            {
                for (var i = 0; i < betweensAnd.Count(); i++)
                {
                    query.AddBetweenAnd(betweensAnd.ElementAt(i));
                }
            }

            return query;
        }

        protected Query AddCustomWheresFilter(Query query, IEnumerable<Where> wheres)
        {
            if (wheres != null)
            {
                wheres.ForEach(w => query.AddWhere(w.ColumnName,
                                                   w.Comparison, w.ParameterValue));
            }

            return query;
        }

        protected Query AddTypeIdFilter(Query query, Guid? typeId, bool withTypeInheritance)
        {
            if (typeId.HasValue)
            {
                if (withTypeInheritance)
                {
                    var type = NodeTypeManager.GetNodeType(typeId.Value);

                    if (type == null)
                    {
                        throw new ArgumentException("NodeType does not exists:" + typeId.Value);
                    }

                    var types = NodeTypeManager.GetAllChildTypes(typeId.Value)
                        .Concat(new[] { type });

                    "TypeId".GetWhereIn(types.Select(t => t.ID).ToList()).ToList()
                        .ForEach(w => query.AddWhere(w));
                }
                else
                {
                    query.AddWhere("TypeId", typeId.Value.ToString());
                }
            }

            return query;
        }

        protected Query AddParentIdFilter(Query query, Guid? parentId, int? depth)
        {
            if (parentId.HasValue)
            {
                var parentDepth = depth ?? 0;

                Node rootNode = null;

                Func<Node> getRootNode = () =>
                                             {
                                                 if (rootNode == null)
                                                 {
                                                     rootNode = NodeManager.GetNode(parentId.Value);

                                                     if (rootNode == null)
                                                     {
                                                         throw new ArgumentException("Parent not found: " +
                                                                                     parentId.Value);
                                                     }
                                                 }

                                                 return rootNode;
                                             };

                if (parentDepth == 1)
                {
                    query.AddWhere("ParentNodeId", Comparison.Equals, parentId.Value);
                }
                else if (parentDepth == 0)
                {
                    query.AddWhere("Path", Comparison.Like,
                                   getRootNode().Path + DataUtil.GetSQLInclusivityOperator(false))
                        .AddWhere("Depth", Comparison.GreaterThan, getRootNode().Depth);
                }
                else
                {
                    query.AddWhere("Path", Comparison.Like,
                                   getRootNode().Path + DataUtil.GetSQLInclusivityOperator(false))
                        .AddWhere("Depth", Comparison.LessOrEquals, getRootNode().Depth + parentDepth)
                        .AddWhere("Depth", Comparison.GreaterThan, getRootNode().Depth);
                }
            }

            return query;
        }

        protected Query AddCultureAndContentStateFilter(bool multiLingual, Query query, ContentState contentState, CultureInfo culture)
        {
            var cultureNames = ConfigManager.GetEditionCultures().Select(c => c.CultureName).ToList();

            if (multiLingual && cultureNames.Count > 1)
            {
                if (contentState != ContentState.All)
                    query.Generation = (int)contentState;

                cultureNames.Remove(culture.Name);
                query.CultureNames = new List<string> { culture.Name }.Union(cultureNames).ToList();
            }
            else
            {
                if (contentState != ContentState.All)
                    query.AddWhere("Generation", (int)contentState);

                if(culture!= null)
                    query.AddWhere("CultureName", culture.Name);
            }

            return query;
        }

        protected Query AddStatusFilter(Query query, ActiveStatus status)
        {
            if (status != ActiveStatus.All)
            {
                query.AddWhere("IsActive", status == ActiveStatus.Activated ? true : false);
            }

            return query;
        }

        public virtual TItem Get(Guid nodeId)
        {
            return Get(nodeId, CultureService.GetCurrentCulture(), ContentStateService.GetCurrentContentState());
        }
        public TItem Get(Guid nodeId, CultureInfo culture, ContentState contentState)
        {
            return Get(nodeId, culture, contentState, ActiveStatus.Activated);
        }

        public virtual TItem Get(Guid nodeId, CultureInfo culture, ContentState contentState, 
            ActiveStatus activeStatus)
        {
            return LoadByIDs(new[] { nodeId }.ToList(), culture.Name, contentState,
                activeStatus).FirstOrDefault();
        }

        public virtual IList<TItem> GetWithFilters(Guid? typeId, Guid? parentId, 
            IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd, string orderByString,
            int? depth, bool withTypeInheritance)
        {
            return GetWithFilters(CultureService.GetCurrentCulture(),
                ContentStateService.GetCurrentContentState(), ActiveStatus.Activated, typeId,
                parentId, wheres, betweensAnd, orderByString, depth, withTypeInheritance);
        }

        public virtual IList<TItem> GetWithFilters(bool multiLingual, Guid? typeId, Guid? parentId,
            IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd, string orderByString,
            int? depth, bool withTypeInheritance)
        {
            return GetWithFilters(multiLingual, CultureService.GetCurrentCulture(),
                ContentStateService.GetCurrentContentState(), ActiveStatus.Activated, typeId,
                parentId, wheres, betweensAnd, orderByString, depth, withTypeInheritance);
        }

        public virtual PagedCollection<TItem> PagedWithFilters(int pageIndex, int pageSize,
            Guid? typeId, Guid? parentId, IEnumerable<Where> wheres, 
            IEnumerable<BetweenAnd> betweensAnd,
            string orderByString, int? depth, bool withTypeInheritance)
        {
            return PagedWithFilters(CultureService.GetCurrentCulture(),
                 ContentStateService.GetCurrentContentState(), ActiveStatus.Activated,
                 pageIndex, pageSize, typeId, parentId, wheres, betweensAnd, orderByString,
                 depth, withTypeInheritance);
        }

        public virtual IList<TItem> ChildsOf(Guid nodeId, bool inclusive, int maxDepth)
        {
            return ChildsOf(nodeId, inclusive, maxDepth, CultureService.GetCurrentCulture(),
                 ContentStateService.GetCurrentContentState(), ActiveStatus.Activated);
        }

        public virtual IList<TItem> ParentsOf(Guid nodeId, bool inclusive, int maxDepth)
        {
            return ParentsOf(nodeId, inclusive, maxDepth, CultureService.GetCurrentCulture(),
                 ContentStateService.GetCurrentContentState(), ActiveStatus.Activated);
        }

        public virtual IEnumerable<TItem> LoadByIDs(string ids)
        {
            return LoadByIDs(ids, CultureService.GetCurrentCulture().Name,
                 ContentStateService.GetCurrentContentState(), ActiveStatus.Activated);
        }

        public virtual IEnumerable<TItem> LoadByIDs(IList<Guid> ids)
        {
            return LoadByIDs(ids, CultureService.GetCurrentCulture().Name,
                 ContentStateService.GetCurrentContentState(), ActiveStatus.Activated);
        }

        public virtual IList<TItem> All()
        {
            return All(CultureService.GetCurrentCulture(),
                 ContentStateService.GetCurrentContentState(), ActiveStatus.Activated);
        }

        public virtual PagedCollection<TItem> PagedWithFilters(CultureInfo culture, int pageIndex, 
            int pageSize, ActiveStatus status, Guid? typeId, Guid? parentId, DateTime? startDate,
            DateTime? endDate, string keywords, string orderBy, 
            IEnumerable<Where> additionalWheres, bool withTypeInheritance)
        {
            return PagedWithFilters(false, culture, pageIndex,
                                    pageSize, status, typeId, parentId, startDate,
                                    endDate, keywords, orderBy,
                                    additionalWheres, null, withTypeInheritance);
        }

        public virtual PagedCollection<TItem> PagedWithFilters(bool multiLingual, CultureInfo culture, int pageIndex,
            int pageSize, ActiveStatus status, Guid? typeId, Guid? parentId, DateTime? startDate,
            DateTime? endDate, string keywords, string orderBy,
            IEnumerable<Where> additionalWheres, IEnumerable<BetweenAnd> additionalBetweenAnds, bool withTypeInheritance)
        {
            var wheres = additionalWheres == null ? new List<Where>() : additionalWheres.ToList();

            if (startDate.HasValue)
            {
                wheres.Add(new Where
                {
                    ColumnName = "CreatedOn",
                    Comparison = Comparison.GreaterOrEquals,
                    ParameterValue = startDate.Value
                });
            }

            if (endDate.HasValue)
            {
                wheres.Add(new Where
                {
                    ColumnName = "CreatedOn",
                    Comparison = Comparison.LessOrEquals,
                    ParameterValue = endDate.Value
                });
            }

            if (!String.IsNullOrEmpty(keywords))
            {
                wheres.Add(new Where
                {
                    ColumnName = "Name",
                    Comparison = Comparison.Like,
                    ParameterValue = '%' + keywords + '%'
                });
            }

            var finalOrderBy = "createdon desc";

            if (!orderBy.IsNullOrEmptyTrim())
                finalOrderBy = orderBy.Trim();

            return PagedWithFilters(multiLingual, culture,
                ContentState.Draft, status, pageIndex,
                pageSize, typeId, parentId,
                wheres, additionalBetweenAnds, finalOrderBy, 1, withTypeInheritance);
        }

        public virtual PagedCollection<TItem> PagedWithFilters(CultureInfo culture, int pageIndex,
            int pageSize, Guid baseTypeId, Guid moduleNodeId, IEnumerable<Where> additionalWheres)
        {
            return PagedWithFilters(culture,ContentState.Draft, ActiveStatus.Activated,
                pageIndex, pageSize, baseTypeId, moduleNodeId, additionalWheres, null, null, 1, true);
        }
    }
}
